package cn.pink.core.support;

import cn.hutool.core.lang.id.NanoId;
import freemarker.template.Configuration;
import freemarker.template.Template;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.math.NumberUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.*;
import java.util.function.Function;

/**
 * 工具类，各种乱七八糟的接口
 * @author Pink
 */
public class Utils {
	/**
	 * 判断两个对象是否相等
	 */
	public static boolean isEquals(Object objA, Object objB) {
		return new EqualsBuilder().append(objA, objB).isEquals();
	}

	/**
	 * 生成nanoId
	 */
	public static String nanoId() {
		return NanoId.randomNanoId(null, "0123456789abcdefghijklmnopqrstuvwxyz".toCharArray(), 21);
	}

	/**
	 * 获取rpc调用处的函数信息，文件名:行号 调用者函数名
	 */
	public static String getCallerInfo() {
		StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
		StackTraceElement e = stackTrace[3];

//		System.out.println("methed name: " + e.getFileName() + " - " + e.getLineNumber() + " - " + e.getMethodName());

		return new StringBuilder().append(e.getFileName()).append(":")
				.append(e.getLineNumber()).append(" ")
				.append(e.getMethodName()).toString();
	}

	/**
	 * bytes TO int（大端格式）
	 */
	public static int bytesToBigEndian32(byte[] b, int offset) {
		return 	(((int)b[offset+0] & 0xff) << 24) |
				(((int)b[offset+1] & 0xff) << 16) |
				(((int)b[offset+2] & 0xff) <<  8) |
				(((int)b[offset+3] & 0xff)      );
	}

	/**
	 * int TO bytes（大端格式）
	 */
	public static void bigEndian32ToBytes(byte[] b, int offset, int value) {
		b[offset+0] = (byte)((value >> 24) & 0xFF);
		b[offset+1] = (byte)((value >> 16) & 0xFF);
		b[offset+2] = (byte)((value >>  8) & 0xFF);
		b[offset+3] = (byte)((value      ) & 0xFF);
	}

	/**
	 * bytes TO int（小端格式）
	 */
	public static int bytesToLittleEndian32(byte[] b, int offset) {
		return  (((int)b[offset+0] & 0xff)      ) |
				(((int)b[offset+1] & 0xff) <<  8) |
				(((int)b[offset+2] & 0xff) << 16) |
				(((int)b[offset+3] & 0xff) << 24);
	}

	/**
	 * int TO bytes（小端格式）
	 */
	public static void littleEndian32ToBytes(byte[] b, int offset, int value) {
		b[offset+0] = (byte)((value      ) & 0xFF);
		b[offset+1] = (byte)((value >>  8) & 0xFF);
		b[offset+2] = (byte)((value >> 16) & 0xFF);
		b[offset+3] = (byte)((value >> 24) & 0xFF);
	}

	/**
	 * FreeMarker生成代码
	 * @param pathPrefix 模板文件所在目录
	 * @param tempFile 模板文件的名字
	 * @param rootMap 要带入模板的变量
	 * @param targetDir 生成文件的目标目录
	 * @param targetFile 生成目标文件的名字
	 */
	public static void freeMarker(String pathPrefix, String tempFile, Object rootMap,
								  String targetDir, String targetFile) throws Exception {
		Configuration configuration = new Configuration();
		configuration.setClassForTemplateLoading(Utils.class, pathPrefix);
		configuration.setEncoding(Locale.getDefault(), "UTF-8");
		Template temp = configuration.getTemplate(tempFile, "UTF-8");

		// 判断目标文件夹不存在 ，则新建文件夹
		File dir = new File(targetDir);
		if (!dir.exists()) {
			dir.mkdirs();
		}

		// 目标文件名(包含路径的名称)
		String fileFullName = targetDir + targetFile;
		System.out.println("---------开始生成" + fileFullName + "文件......---------");

		// 根据模版生成文件
		File target = new File(fileFullName);
		Writer out = new OutputStreamWriter(new FileOutputStream(target), "UTF-8");
		temp.process(rootMap, out);
		out.flush();
		out.close();

		System.out.println("---------" + targetFile + "文件生成完毕！---------\n");
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Integer> ofList(int[] ts) {
		List<Integer> result = new ArrayList<>();
		for (int t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Long> ofList(long[] ts) {
		List<Long> result = new ArrayList<>();
		for (long t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Float> ofList(float[] ts) {
		List<Float> result = new ArrayList<>();
		for (float t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Double> ofList(double[] ts) {
		List<Double> result = new ArrayList<>();
		for (double t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Byte> ofList(byte[] ts) {
		List<Byte> result = new ArrayList<>();
		for (byte t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Character> ofList(char[] ts) {
		List<Character> result = new ArrayList<>();
		for (char t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Short> ofList(short[] ts) {
		List<Short> result = new ArrayList<>();
		for (short t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	public static List<Boolean> ofList(boolean[] ts) {
		List<Boolean> result = new ArrayList<>();
		for (boolean t : ts) {
			result.add(t);
		}

		return result;
	}

	/**
	 * 数组或者多个参数转成list
	 */
	@SafeVarargs
	public static <T> List<T> ofList(T...ts) {
		return Arrays.asList(ts);
	}

	//--------------------------------------------------------------------------------
	// convert，各种类型间相互转换

	/**
	 * String TO int<br>
	 * 如果出错 则为0
	 */
	public static int intValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Double.valueOf(value).intValue();
		} else {
			System.err.println("数据错误:" + value);
			return 0;
		}
	}

	/**
	 * String TO long<br>
	 * 如果出错 则为0
	 */
	public static long longValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Long.parseLong(value);
		} else {
			return 0L;
		}
	}

	/**
	 * String TO float<br>
	 * 如果出错 则为0.0
	 */
	public static float floatValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Float.valueOf(value);
		} else {
			return 0.0f;
		}
	}

	/**
	 * String TO double<br>
	 * 如果出错 则为0.0
	 */
	public static double doubleValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value)) {
			return Double.valueOf(value);
		} else {
			return 0.0D;
		}
	}

	/**
	 * String TO boolean<br>
	 * 如果出错 则为false
	 */
	public static boolean booleanValue(String value) {
		if ("true".equalsIgnoreCase(value) && value != null) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * str TO int[]<br>
	 * eg: "1,2" TO [1, 2]
	 */
	public static int[] parseIntArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new int[0];
		}

		String[] elems = value.split(",");
		int[] result = new int[elems.length] ;
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.intValue(elems[i]);
		}

		return result;
	}

	public static int[] parseIntArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return Empty.intArray;
		}

		String[] elems = value.split(split);
		int[] result = new int[elems.length];
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.intValue(elems[i]);
		}

		return result;
	}

	/**
	 * str TO long[]<br>
	 * eg: "1,2" TO [1, 2]
	 */
	public static long[] parseLongArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new long[0];
		}

		String[] elems = value.split(",");
		long[] result = new long[elems.length] ;
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.longValue(elems[i]);
		}

		return result;
	}

	public static long[] parseLongArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return Empty.longArray;
		}

		String[] elems = value.split(split);
		long[] result = new long[elems.length];
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.longValue(elems[i]);
		}

		return result;
	}

	/**
	 * str TO float[]<br>
	 * eg: "1.0,2.0" TO [1.0, 2.0]
	 */
	public static float[] parseFloatArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new float[0];
		}

		String[] elems = value.split(",");
		float[] result = new float[elems.length] ;
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.floatValue(elems[i]);
		}

		return result;
	}

	public static float[] parseFloatArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return Empty.floatArray;
		}

		String[] elems = value.split(split);
		float[] result = new float[elems.length];
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.floatValue(elems[i]);
		}

		return result;
	}

	/**
	 * str TO double[]<br>
	 * eg: "1.0,2.0" TO [1.0, 2.0]
	 */
	public static double[] parseDoubleArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new double[0];
		}

		String[] elems = value.split(",");
		double[] result = new double[elems.length] ;
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.doubleValue(elems[i]);
		}

		return result;
	}

	public static double[] parseDoubleArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return Empty.doubleArray;
		}

		String[] elems = value.split(split);
		double[] result = new double[elems.length];
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.doubleValue(elems[i]);
		}

		return result;
	}

	/**
	 * str TO str[]<br>
	 * eg: "1,2" TO ["1", "2"]
	 */
	public static String[] parseStringArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new String[0];
		}

		return value.split(",");
	}

	public static String[] parseStringArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return new String[0];
		}

		return value.split(split);
	}

	/**
	 * str TO boolean[]<br>
	 * eg: "true,false" TO [true, false]
	 */
	public static boolean[] parseBoolArray(String value) {
		if (StringUtils.isBlank(value)) {
			return new boolean[0];
		}

		String[] elems = value.split(",");
		boolean[] result = new boolean[elems.length] ;
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.booleanValue(elems[i]);
		}

		return result;
	}

	public static boolean[] parseBoolArray(String value, String split) {
		if (StringUtils.isBlank(value)) {
			return Empty.booleanArray;
		}

		String[] elems = value.split(split);
		boolean[] result = new boolean[elems.length];
		for (int i = 0; i < elems.length; i++) {
			result[i] = Utils.booleanValue(elems[i]);
		}

		return result;
	}

	/**
	 * str TO int list<br>
	 * eg: "1,2" TO {1, 2}
	 */
	public static List<Integer> parseIntList(String value) {
		List<Integer> result = new ArrayList<>();
		if (StringUtils.isBlank(value)) {
			return result;
		}

		String[] elems = value.split(",");
		for (int i = 0; i < elems.length; i++) {
			result.add(Utils.intValue(elems[i]));
		}

		return result;
	}

	/**
	 * 将11:572,21:32,31:28,41:100,51:5,61:0.03这种格式的字符串转成map
	 */
	public static <K, V> Map<K, V> parseMap(String str, Function<String, K> keyConvert, Function<String, V> valueConvert) {
		Map<K, V> map = new HashMap<>();
		if (StringUtils.isEmpty(str)) {
			return map;
		}

		String[] params = str.split(",");
		for (String param : params) {
			if (!param.contains(":")) {
				continue;
			}

			String[] words = param.split(":");
			K key = keyConvert.apply(words[0]);
			V value = valueConvert.apply(words[1]);
			map.put(key, value);
		}

		return map;
	}
	/**
	 * 将map转换成"key1:value1,key2:value2,"这种格式的字符串
	 */
	public static <K,V> String mapParseString(Map<K,V> map) {
		if(map.isEmpty()) {
			return "";
		}
		StringBuilder sb = new StringBuilder();
		for (K key : map.keySet()) {
			sb.append(String.valueOf(key))
					.append(":")
					.append(String.valueOf(map.get(key)))
					.append(",");
		}
		return sb.toString();
	}

	public static Map<Integer, Float> array2MapIF(float[][] param){
		Map<Integer, Float> map = new HashMap<>();
		for (float[] v : param) {
			map.merge((int)v[0], v[1], Float::sum);
		}
		return map;
	}

}
